#include <iostream>
#include <pthread.h>
#include <vector>
#include <unistd.h>
#include <string>
#include <cstring>
#include "LockGuard.hpp"

using namespace std;

#define NUM 4

class threadData
{
public:
    threadData(int number/*,pthread_mutex_t *mutex*/)
    {
        _threadname = "thread-" + to_string(number);
        //_lock = mutex;
    }
public:
    string _threadname;
    // pthread_mutex_t *_lock;
};

int tickets = 3000;//模拟一轮多线程抢票的场景
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;

void *getTicket(void *args)
{
    threadData* td = static_cast<threadData*>(args);
    const char* name = td->_threadname.c_str();

    while(true)
    {
        //不同线程对锁的竞争能力可能不同
        //pthread_mutex_lock(&lock);//申请成功才能往后执行，否则，阻塞等待
        {   
            LockGuard lockguard(&lock);     
            if(tickets > 0)
            {
                usleep(1000);
                printf("who : %s, get a ticket :%d\n",name,tickets);
                tickets--;
                //pthread_mutex_unlock(&lock);
            }
            else
            {
                //pthread_mutex_unlock(&lock);
                break;
            }
        }

        usleep(13);//现实中，抢票后还会有后续动作，这里是模拟后续动作 
    }
    
     printf("%s ... quit\n", name);

    return nullptr;
}

int main()
{
    // pthread_mutex_init(&lock,nullptr);
    vector<pthread_t> tids;
    vector<threadData*> threadDatas;

    for(int i = 1; i <= NUM; i++)
    {
        pthread_t tid;
        threadData* td = new threadData(i);
        threadDatas.push_back(td);
        pthread_create(&tid,nullptr,getTicket,threadDatas[i - 1]);
        tids.push_back(tid);
    }

    for(auto thread : tids)
    {
        pthread_join(thread,nullptr);
    }

    for(auto &e : threadDatas)
    {
        delete e;
    }
    // pthread_mutex_destroy(&lock);
    return 0;
}


// //int *p = nullptr;

// //__thread int g_val = 100;
// // 将g_val定义在线程的局部存储
// //__thread 只能修饰内置类型

// __thread unsigned int number = 0;
// __thread int pid = 0;


// struct threadData
// {
//     string threadname;
// };

// string toHex(pthread_t tid)
// {
//     char buffer[128];
//     snprintf(buffer,sizeof(buffer),"0x%x",tid);
//     return buffer;
// }

// void InitThread(threadData *td, int num)
// {
//     td->threadname = "thread-" + to_string(num);// "thread-0"
// }

// void *threadRun(void *args)
// {
//     pthread_detach(pthread_self()); //一个线程不仅可以被主进程分离，也可以由线程自己分离。

//     //int test_i = 0;
//     threadData* td = static_cast<threadData*>(args);
//     // if(td->threadname == "thread-1")
//     //     p = &test_i;
//     int i = 0;

//     pid = getpid();
//     number = pthread_self();

//     while(i < NUM)
//     {
//         cout << "tid :" << toHex(number) << ", pid :" << pid << endl;
//         // cout << "pid :" << getpid() << ", tid :" << toHex(pthread_self())
//         //     << ", threadname :" << td->threadname << ",g_val :" << g_val  
//         //     << ", &g_val :" << &g_val << endl;
//         sleep(1);
//         //g_val++;
//         i++;
//     }
//     delete td;
//     return nullptr;
// }

// int main()
// {
//     vector<pthread_t> tids;
//     for(int i = 0;i < NUM; i++)
//     {
//         pthread_t tid;
//         threadData* td = new threadData;
//         InitThread(td,i);
//         pthread_create(&tid,nullptr,threadRun,td);
//         tids.push_back(tid);
//         //sleep(1);
//     }

//     // sleep(1);//确保能够读到变量
//     // cout << "main thread get a value : " << *p 
//     // << ",&value is : " << p << endl;
//     //结论：同一进程内的不同线程间是没有秘密的


//     //pthead_datach 用于 分离线程。即线程退出后，资源会被操作系统回收释放
//     // for(auto e: tids)
//     // {
//     //     pthread_detach(e);
//     // }

//     //joinable和分离是冲突的，一个线程不能即是joinable又是分离的

//     for(int i = 0; i < tids.size(); i++)
//     {
//         int n = pthread_join(tids[i],nullptr);
//         printf("n = %d, who : 0x%x, why : %s\n",n,tids[i],strerror(n));
//     }

//     return 0;
// }
